package org.example;


import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Test4 {

    private static List<Device> deviceList=new ArrayList<>();

    static {



//        deviceList.add(new Device(
//                "DWGZCJY231122999",
//                "0227f5e05f00990001014457475a434a59323331313232393939322e30312e3030323501088ee05f38363538363630363838323932383034363030383732333130303730373438393836303446323130323344313036373037341000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005ffd0d0a",
//                "022af5e05f04212000eec80000983fbd86760100000820800100f6487644f7447644f44c7644e66e7644e07c7644ea647644022a7644de817644ee5c7644e5707644f1537644e66f7644f1537644f7467644ec617644f1537644e5707644e66e7644f44d7644f34f7644ef597644db897644f44c7644ec607644f2507644ef597644e76c7644e2797644e9677644f9407644ea647644e86a764402020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d0b10d0a",
//                "8channel",
//                new AtomicInteger(0)
//        ));

    }

    public static void main(String[] args) throws InterruptedException {



     test();
    }


    public static void test() throws InterruptedException {
        deviceList.clear();
        String prex="TEST";
        long max= 111111111399L;
        long min= 111111111001L;
        for (long i=min;i<=max;i++){
            deviceList.add(new Device(
                    prex+i,
                    "0266f9676500990001014457475a434a59323331303237303133312e30312e3030303901e8986765383635313337303631303430363833343630303834353433373033333036383938363034433531303232323032373333303616bd022c0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000af630d0a",
                    "0226766D3800430110043836353235373036323037353330343839383630343931313032313831363939303537312E30302E3030303101020304010F00780028326464056400640000000176A40D0A",
                    "dizhen",
                    new AtomicInteger(0)
            ));
        }
        System.out.println("启动+"+deviceList.size()+"个设备");
        for (int i = 0; i < deviceList.size(); i++) {
            NioEventLoopGroup worker = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(worker);
            bootstrap.option(NioChannelOption.TCP_NODELAY, true);
            int currendIndex = i;
            Device device = deviceList.get(currendIndex);
            int finalI = i;
            bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                        //和服务器建立连接之后的回调
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            System.out.println("连接建立");
                            //执行登录
                            ByteBuf loginBuf = dynamicClientId(device.clientLoginCommand, device.clientId);
                            //CRC16CCTT校验
                            int crcIndexLogin = loginBuf.readableBytes() - 4;
                            byte[] crcBytesnLogin = crc16CCITTFalse(ByteBufUtil.getBytes(loginBuf,0,crcIndexLogin));
                            loginBuf.setBytes(crcIndexLogin,crcBytesnLogin);
                            ctx.writeAndFlush(loginBuf);
                            TimeUnit.SECONDS.sleep(20);
                            for (int i=0;i<1000;i++){
                                ByteBuf byteBuf = dynamicTime(device.protolType, device.clientPublishCommand);
                                //CRC16CCTT校验
                                int crcIndex = byteBuf.readableBytes() - 4;
                                byte[] crcBytes = crc16CCITTFalse(ByteBufUtil.getBytes(byteBuf,0,crcIndex));
                                byteBuf.setBytes(crcIndex,crcBytes);

                                ctx.writeAndFlush(byteBuf);
                                TimeUnit.MILLISECONDS.sleep(300);
                                int get = device.publishNumber.incrementAndGet();
                                System.out.println("设备"+device.clientId+" 发送了"+get+"次");
                            }
                            //关闭
                            TimeUnit.SECONDS.sleep(3);
                            ctx.close();
                        }

                        @Override
                        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                            System.out.println("断开连接了。。。");
                            ctx.fireChannelInactive();
                        }

                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            ByteBuf buf= (ByteBuf) msg;
                            String s = ByteBufUtil.hexDump(buf);
                            System.out.println("确认包："+s);
                        }
                    });
                }
            });// 测试 47.110.35.104  本地 58.216.200.114    124.70.211.143
            ChannelFuture channelFuture = bootstrap.connect("121.224.59.50", 8765).sync();
            Channel channel = channelFuture.channel();
        }
    }
    private static ByteBuf dynamicClientId(String clientLoginCommand,String clientId) {
        byte[] bytes = ByteBufUtil.decodeHexDump(clientLoginCommand);
        ByteBuf byteBuf = Unpooled.buffer().writeBytes(bytes);
        byteBuf.setBytes(10,clientId.getBytes());
        return byteBuf;
    }

    private static ByteBuf dynamicTime(String protolType,String command){
        Date date = new Date();
        long time = date.getTime();
        byte[] bytes = ByteBufUtil.decodeHexDump(command);
        ByteBuf byteBuf = Unpooled.buffer().writeBytes(bytes);
        if (protolType.equals("dizhen")){
            //秒
            int second = (int) (time / 1000);
            byteBuf.setIntLE(9,second);
        } else if (protolType.equals("8channel")) {
            //毫秒
            byteBuf.setLongLE(13,time);
            System.out.println("毫秒："+time);
        }
        return byteBuf;
    }

    public static byte[] crc16CCITTFalse(byte[] bytes) {
        int crc = 0xffff; // initial value
        int polynomial = 0x1021; // poly value
        for (int index = 0; index < bytes.length; index++) {
            byte b = bytes[index];
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b >> (7 - i) & 1) == 1);
                boolean c15 = ((crc >> 15 & 1) == 1);
                crc <<= 1;
                if (c15 ^ bit){
                    crc ^= polynomial;
                }
            }
        }
        crc &= 0xffff;
        return new byte[] { (byte) ((0xff00 & crc) >> 8),(byte) (0xff & crc)  };
    }

    static class Device{
        public String clientId;
        public String clientLoginCommand;
        public String clientPublishCommand;
        public String protolType;
        private AtomicInteger publishNumber;

        public Device(String clientId,String clientLoginCommand, String clientPublishCommand, String protolType,AtomicInteger publishNumber) {
            this.clientId=clientId;
            this.clientLoginCommand = clientLoginCommand;
            this.clientPublishCommand = clientPublishCommand;
            this.protolType = protolType;
            this.publishNumber=publishNumber;
        }
    }
}
